package com.yiduo.outpost.gateway.filter;

import com.yiduo.outpost.core.redis.props.RedisConstant;
import com.yiduo.outpost.core.security.TokenProvider;
import com.yiduo.outpost.core.security.UnAuthorizedException;
import com.yiduo.outpost.core.security.jwt.JwtTokenGenerator;
import com.yiduo.outpost.gateway.service.UserPermissionMatcher;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.Set;

@Slf4j
@Component
public class ApiPermissionGlobalFilter implements GlobalFilter, Ordered {
	@Autowired
	private JwtTokenGenerator jwtTokenGenerator;
	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	@Autowired
	private UserPermissionMatcher userPermissionMatcher;

	/**
	 * 过滤用户有没有登录访问权限
	 *
	 * @param exchange the current server exchange
	 * @param chain    provides a way to delegate to the next filter
	 * @return
	 */
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpRequest request = exchange.getRequest();
		//用户完整的请求地址 originRequest
		Set<URI> lbUri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
		String path = lbUri.stream().findFirst().get().getPath();
		//获取目标服务的请求地址
		String url = request.getPath().value();
		HttpMethod method = request.getMethod();
		MultiValueMap<String, String> parameterMap = request.getQueryParams();
		// 非登录接口直接放行（权限匹配器 不需要登录）
		if (HttpMethod.OPTIONS.equals(method) || userPermissionMatcher.isPermitAll(url, method.name(), parameterMap)) {
			return chain.filter(exchange);
			//.then(Mono.fromRunnable(TenantContextHolder::clearContext));
		}

		String token = jwtTokenGenerator.extractToken(request);
		// 校验jwt的token的合法性
		if (token == null || !jwtTokenGenerator.validateToken(token)) {
			throw new UnAuthorizedException();
		}

		// 解析jwt-token，获取加密参数对象Claims
		Claims claims = jwtTokenGenerator.extractClaimsFromToken(token);
		// 如果referer获取不到数据源,尝试从token中解析
		Long userId = claims.get(TokenProvider.USER_ID_KEY, Long.class);
		//已经登录的用户token
		String longToken = redisTemplate.opsForValue().get(RedisConstant.USER_SESSION_TOKEN_KEY + userId);
		if (StringUtils.equals(token, longToken)) {
			return chain.filter(exchange);
			//.then(Mono.fromRunnable(TenantContextHolder::clearContext));
		}
		throw new UnAuthorizedException();
	}

	@Override
	public int getOrder() {
		return LOWEST_PRECEDENCE - 2;
	}
}